//
// Created by sxt on 2023/10/18.
//

#ifndef MY_REFLECT_METHOD_H
#define MY_REFLECT_METHOD_H

#include <string>
#include <any>
#include <tuple>

namespace myreflect {
    using namespace std;

    class RawTypeDescriptorBuilder;

    /**
     * 方法
     */
    class Method {

        // 声明RawTypeDescriptorBuilder为友元 供该类访问本类的私有成员
        friend class RawTypeDescriptorBuilder;

    public:

        /**
         * 构造一个非const 有返回值的方法描述对象
         * @tparam Class 方法所在类
         * @tparam Return 方法返回值类型
         * @tparam Args 方法参数
         * @param func 方法指针
         */
        template<class Class, typename Return, typename ...Args>
        explicit Method(Return (Class::*func)(Args...)) {
            this->func = [func] (any objAndArgs) -> any {
                using tuple_t = tuple<Class &, Args...>;
                auto *tp_ptr = any_cast<tuple_t *>(objAndArgs);
                return apply(func, *tp_ptr);
            };
        }

        /**
         * 构造一个非const 无返回值的方法描述对象
         * @tparam Class 方法所在类
         * @tparam Args 方法参数
         * @param func 方法指针
         */
        template<class Class, typename ...Args>
        explicit Method(void (Class::*func)(Args...)) {
            this->func = [func] (any objAndArgs) -> any {
                using tuple_t = tuple<Class &, Args...>;
                auto *tp_ptr = any_cast<tuple_t *>(objAndArgs);
                apply(func, *tp_ptr);
                return any{};
            };
        }

        /**
         * 构造一个const 有返回值的方法描述对象
         * @tparam Class 方法所在类
         * @tparam Return 方法返回值类型
         * @tparam Args 方法参数
         * @param func 方法指针
         */
        template<class Class, typename Return, typename ...Args>
        explicit Method(Return (Class::*func)(Args...) const) {
            this->func = [func] (any objAndArgs) -> any {
                using tuple_t = tuple<const Class &, Args...>;
                auto *tp_ptr = any_cast<tuple_t *>(objAndArgs);
                return apply(func, *tp_ptr);
            };
            isConst = true;
        }

        /**
         * 构造一个const 无返回值的方法描述对象
         * @tparam Class 方法所在类
         * @tparam Args 方法参数
         * @param func 方法指针
         */
        template<class Class, typename ...Args>
        explicit Method(void (Class::*func)(Args...) const) {
            this->func = [func] (any objAndArgs) -> any {
                using tuple_t = tuple<const Class &, Args...>;
                auto *tp_ptr = any_cast<tuple_t *>(objAndArgs);
                apply(func, *tp_ptr);
                return any{};
            };
            isConst = true;
        }

    public:

        /**
         * 方法执行
         * @tparam Class 方法
         * @tparam Args
         * @param cls
         * @param args
         * @return
         */
        template<class Class, typename ...Args>
        any invoke(Class &cls, Args &&... args) {
            if (isConst) {
                auto tp = make_tuple(reference_wrapper<const Class>(cls), args...);
                return func(&tp);
            } else {
                auto tp = make_tuple(reference_wrapper<Class>(cls), args...);
                return func(&tp);
            }
        }

        /**
         * 获取该方法是否const
         * @return 该方法是否const
         */
        [[nodiscard]] bool isConstMethod() const;

        [[nodiscard]] const string &getMethodName() const;

    private:
        /**
         * 方法名
         */
        string methodName;

        /**
         * 是否const方法
         */
        bool isConst{false};

        /**
         * 方法执行逻辑
         */
        function<any(any)> func{nullptr};
    };
}

#endif //MY_REFLECT_METHOD_H
